# Copyright (c) 2025 Shenzhen Kaihong Digital Industry Development Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import struct
import zlib

# bool
# byte
# char
# duration
# float32
# float64
# int16
# int32
# int64
# int8
# string
# time
# uint16
# uint32
# uint64
# uint8
g_msg_count = 0


class PackageTool:
    def __init__(self, buffer=[]):
        self.buffer = bytearray(buffer)
        self.offset = 0

    def compress(self):
        self.buffer = zlib.compress(self.buffer)
        
    def decompress(self):
        self.buffer = zlib.decompress(self.buffer)

    def put_bool(self, value):
        self.buffer.extend(struct.pack("<?", value))

    def put_byte(self, value):
        self.buffer.extend(struct.pack("<B", value))

    def put_char(self, value):
        self.buffer.extend(value.encode("utf-8"))

    def put_duration(self, value):
        self.buffer.extend(struct.pack("<i", value.secs))
        self.buffer.extend(struct.pack("<i", value.nsecs))

    def put_float32(self, value):
        self.buffer.extend(struct.pack("<f", value))

    def put_float64(self, value):
        self.buffer.extend(struct.pack("<d", value))

    def put_int16(self, value):
        self.buffer.extend(struct.pack("<h", value))

    def put_int32(self, value):
        self.buffer.extend(struct.pack("<i", value))

    def put_int64(self, value):
        self.buffer.extend(struct.pack("<q", value))

    def put_int8(self, value):
        self.buffer.extend(struct.pack("<b", value))

    def put_string(self, value):
        tv = value.encode("utf-8")
        self.put_uint32(len(tv))
        self.buffer.extend(tv)

    def put_time(self, value):
        self.buffer.extend(struct.pack("<i", value.secs))
        self.buffer.extend(struct.pack("<i", value.nsecs))

    def put_uint16(self, value):
        self.buffer.extend(struct.pack("<H", value))

    def put_uint32(self, value):
        self.buffer.extend(struct.pack("<I", value))

    def put_uint64(self, value):
        self.buffer.extend(struct.pack("<Q", value))

    def put_uint8(self, value):
        self.buffer.extend(struct.pack("<B", value))

    def put_bool_array(self, value):
        self.put_uint32(len(value))
        for v in value:
            self.put_bool(v)

    def put_byte_array(self, value):
        self.put_uint32(len(value))
        # for v in value:
        #     self.put_byte(v)
        self.buffer.extend(value)

    def put_char_array(self, value):
        self.put_uint32(len(value))
        for v in value:
            self.put_char(v)

    def put_duration_array(self, value):
        self.put_uint32(len(value))
        for v in value:
            self.put_duration(v)

    def put_float32_array(self, value):
        self.put_uint32(len(value))
        for v in value:
            self.put_float32(v)

    def put_float64_array(self, value):
        self.put_uint32(len(value))
        for v in value:
            self.put_float64(v)

    def put_int16_array(self, value):
        self.put_uint32(len(value))
        for v in value:
            self.put_int16(v)

    def put_int32_array(self, value):
        self.put_uint32(len(value))
        for v in value:
            self.put_int32(v)

    def put_int64_array(self, value):
        self.put_uint32(len(value))
        for v in value:
            self.put_int64(v)

    def put_int8_array(self, value):
        self.put_uint32(len(value))
        for v in value:
            self.put_int8(v)

    def put_string_array(self, value):
        self.put_uint32(len(value))
        for v in value:
            self.put_string(v)

    def put_time_array(self, value):
        self.put_uint32(len(value))
        for v in value:
            self.put_time(v)

    def put_uint16_array(self, value):
        self.put_uint32(len(value))
        for v in value:
            self.put_uint16(v)

    def put_uint32_array(self, value):
        self.put_uint32(len(value))
        for v in value:
            self.put_uint32(v)

    def put_uint64_array(self, value):
        self.put_uint32(len(value))
        for v in value:
            self.put_uint64(v)

    def put_uint8_array(self, value):
        self.put_uint32(len(value))
        # for v in value:
        #     self.put_uint8(v)
        self.buffer.extend(value)

        # global g_msg_count
        # g_msg_count += 1
        # import zlib

        # zvalue = zlib.compress(value)
        # self.put_uint32(len(zvalue))
        # self.buffer.extend(zvalue)
        # print(g_msg_count, len(value), "=>", len(zvalue))

    def get_bool(self):
        ret = struct.unpack("<?", self.buffer[self.offset : self.offset + 1])[0]
        self.offset += 1
        return ret == 1

    def get_byte(self):
        ret = struct.unpack("<B", self.buffer[self.offset : self.offset + 1])[0]
        self.offset += 1
        return ret

    def get_char(self):
        ret = self.buffer[self.offset : self.offset + 1].decode("utf-8")
        self.offset += 1
        return ret

    def get_duration(self):
        secs = struct.unpack("<i", self.buffer[self.offset : self.offset + 4])[0]
        self.offset += 4
        nsecs = struct.unpack("<i", self.buffer[self.offset : self.offset + 4])[0]
        self.offset += 4
        return {"secs": secs, "nsecs": nsecs}

    def get_float32(self):
        ret = struct.unpack("<f", self.buffer[self.offset : self.offset + 4])[0]
        self.offset += 4
        return ret

    def get_float64(self):
        ret = struct.unpack("<d", self.buffer[self.offset : self.offset + 8])[0]
        self.offset += 8
        return ret

    def get_int16(self):
        ret = struct.unpack("<h", self.buffer[self.offset : self.offset + 2])[0]
        self.offset += 2
        return ret

    def get_int32(self):
        ret = struct.unpack("<i", self.buffer[self.offset : self.offset + 4])[0]
        self.offset += 4
        return ret

    def get_int64(self):
        ret = struct.unpack("<q", self.buffer[self.offset : self.offset + 8])[0]
        self.offset += 8
        return ret

    def get_int8(self):
        ret = struct.unpack("<b", self.buffer[self.offset : self.offset + 1])[0]
        self.offset += 1
        return ret

    def get_string(self):
        length = self.get_uint32()
        ret = self.buffer[self.offset : self.offset + length].decode("utf-8")
        self.offset += length
        return ret

    def get_time(self):
        secs = struct.unpack("<i", self.buffer[self.offset : self.offset + 4])[0]
        self.offset += 4
        nsecs = struct.unpack("<i", self.buffer[self.offset : self.offset + 4])[0]
        self.offset += 4
        return {"secs": secs, "nsecs": nsecs}

    def get_uint16(self):
        ret = struct.unpack("<H", self.buffer[self.offset : self.offset + 2])[0]
        self.offset += 2
        return ret

    def get_uint32(self):
        ret = struct.unpack("<I", self.buffer[self.offset : self.offset + 4])[0]
        self.offset += 4
        return ret

    def get_uint64(self):
        ret = struct.unpack("<Q", self.buffer[self.offset : self.offset + 8])[0]
        self.offset += 8
        return ret

    def get_uint8(self):
        ret = struct.unpack("<B", self.buffer[self.offset : self.offset + 1])[0]
        self.offset += 1
        return ret

    def get_bool_array(self):
        length = self.get_uint32()
        ret = []
        for i in range(length):
            ret.append(self.get_bool())
        return ret

    def get_byte_array(self):
        length = self.get_uint32()
        # ret = []
        # for i in range(length):
        #     ret.append(self.get_byte())
        # return ret
        ret = self.buffer[self.offset : self.offset + length]
        self.offset += length
        return ret

    def get_char_array(self):
        length = self.get_uint32()
        ret = []
        for i in range(length):
            ret.append(self.get_char())
        return ret

    def get_duration_array(self):
        length = self.get_uint32()
        ret = []
        for i in range(length):
            ret.append(self.get_duration())
        return ret

    def get_float32_array(self):
        length = self.get_uint32()
        ret = []
        for i in range(length):
            ret.append(self.get_float32())
        return ret

    def get_float64_array(self):
        length = self.get_uint32()
        ret = []
        for i in range(length):
            ret.append(self.get_float64())
        return ret

    def get_int16_array(self):
        length = self.get_uint32()
        ret = []
        for i in range(length):
            ret.append(self.get_int16())
        return ret

    def get_int32_array(self):
        length = self.get_uint32()
        ret = []
        for i in range(length):
            ret.append(self.get_int32())
        return ret

    def get_int64_array(self):
        length = self.get_uint32()
        ret = []
        for i in range(length):
            ret.append(self.get_int64())
        return ret

    def get_int8_array(self):
        length = self.get_uint32()
        ret = []
        for i in range(length):
            ret.append(self.get_int8())
        return ret

    def get_string_array(self):
        length = self.get_uint32()
        ret = []
        for i in range(length):
            ret.append(self.get_string())
        return ret

    def get_time_array(self):
        length = self.get_uint32()
        ret = []
        for i in range(length):
            ret.append(self.get_time())
        return ret

    def get_uint16_array(self):
        length = self.get_uint32()
        ret = []
        for i in range(length):
            ret.append(self.get_uint16())
        return ret

    def get_uint32_array(self):
        length = self.get_uint32()
        ret = []
        for i in range(length):
            ret.append(self.get_uint32())
        return ret

    def get_uint64_array(self):
        length = self.get_uint32()
        ret = []
        for i in range(length):
            ret.append(self.get_uint64())
        return ret

    def get_uint8_array(self):
        length = self.get_uint32()
        ret = []
        for i in range(length):
            ret.append(self.get_uint8())
        return ret
